/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#include "Tracer.h"
#include "SqliteWrapper.h"

#ifdef OS_CYGWIN
#else
namespace libemb{
SqliteWrapper::SqliteWrapper()
{
    m_db = NULL;
}
SqliteWrapper::~SqliteWrapper()
{
    this->close();
}

/**
 *  \brief  打开数据库
 *  \param  dbName 数据库名字
 *  \return 成功返回true,失败返回false
 *  \note   如果dbName=":memory",表示打开内存数据库
 */
bool SqliteWrapper::open(std::string dbName)
{
    int ret;
    if (dbName.empty())
    {
        return false;
    }
    if (m_db != NULL)
    {
        TRACE_ERR_CLASS("sqlite database is allready open!\n");
        return false;
    }
    ret = sqlite3_open(dbName.c_str(),&m_db);
    if (ret!=SQLITE_OK)
    {
        TRACE_ERR_CLASS("sqlite_open error:%d.\n",ret);
        return false;
    }
    return true;
}

/**
 *  \brief  连接数据库
 *  \param  user 用户名
 *  \param  passwd 密码
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool SqliteWrapper::connect(std::string user, std::string passwd)
{
    return false;
}
/**
 *  \brief  关闭数据库
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool SqliteWrapper::close()
{
    if(m_db!=NULL)
    {
        sqlite3_close(m_db);
        m_db = NULL;
    }
    return true;
}
/********************************************************************
 *  回调函数举例,tbl_contacts如下:
 *  nama 	num
 *  fergus	123456
 *  cblock	789012
 *  somebody NULL
 *  "select * from tbl_contacts"每取出一条记录后都将执行一次回调函数,
 *  回调函数的参数值第一次执行回调函数:
 *  n_column=2,//该条记录有两个字段(两列)
 *  column_value[]={"fergus","12456"};
 *  column_name[]={"name","num"};
 *  第二次执行回调函数:
 *  n_column=2,//该条记录有两个字段(两列)
 *  column_value[]={"cblock","789012"};
 *  column_name[]={"name","num"};
 ********************************************************************/
static int stringSQLResult(void*para,int columns,char**column_value,char**column_name)
{
   SqlResult_S* result=(SqlResult_S*)para;
   result->m_columns = columns;
    for(int i=0; i<columns; i++)
    {
        std::string value;
        if (column_value[i]==NULL)
        {
            value="";
        }
        else
        {
            value = column_value[i];
        }
        result->m_resultStrVect.push_back(value);
    }
    return 0;
}
/**
 *  \brief  执行SQL语句
 *  \param  sql SQL语句
 *  \param  result SQL执行结果
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool SqliteWrapper::exec(const std::string& sql,SqlResult_S* result)
{
    char* errMsg=NULL;
    AutoLock lock(&m_dbLock);
    if (sql.empty())
    {
        return false;   
    }
    if(result==NULL)
    {
        if (sqlite3_exec(m_db, sql.c_str() , NULL , NULL, &errMsg ) != SQLITE_OK)
        {
            TRACE_ERR_CLASS("sql [%s] failed,error msg:%s\n", sql.c_str(),errMsg);
            return false;
        }
    }
    else
    {
        result->m_resultStrVect.clear();
        if (sqlite3_exec(m_db, sql.c_str() , stringSQLResult , (void*)result, &errMsg ) != SQLITE_OK)
        {
            TRACE_ERR_CLASS("sql [%s] failed,error msg:%s\n", sql.c_str(),errMsg);
            return false;
        }
    }
    return true;
}

/**
 *  \brief  插入二进制数据
 *  \param  sql SQL插入语句
 *  \param  bindVarName 绑定变量名,格式为":name"
 *  \param  buf 数据缓存
 *  \param  len 数据长度
 *  \return 成功返回true,失败返回false
 *  \note   每次只允许插入一条记录
 */
bool SqliteWrapper::insertBlob(const std::string& sql,std::string bindVarName,char* buf, int len)
{
    sqlite3_stmt* pStmt;
    int colIndex = 0;
    if (SQLITE_OK != sqlite3_prepare(m_db, sql.c_str(), -1, &pStmt, NULL))
    {
        TRACE_ERR_CLASS("sqlite3_prepare error.\n");
        sqlite3_finalize(pStmt);
        return false;
    }

    colIndex = sqlite3_bind_parameter_index(pStmt,bindVarName.c_str());
    if (SQLITE_OK != sqlite3_bind_blob(pStmt, colIndex+1, buf, len, NULL))
    {
        TRACE_ERR_CLASS("sqlite3_bind_blob error,col=%d.\n",colIndex);
        sqlite3_finalize(pStmt);
        return false;
    }

    if (SQLITE_DONE != sqlite3_step(pStmt))
    {
        TRACE_ERR_CLASS("sqlite3_step error or not finished.\n");
        sqlite3_finalize(pStmt);
        return false;
    }

    sqlite3_finalize(pStmt);
    return true;
}

/**
 *  \brief  读取二进制数据
 *  \param  sql SQL查询语句
 *  \param  bindVarName 绑定变量名,格式为":name"
 *  \param  buf 数据缓存
 *  \param  len 数据长度
 *  \return 成功返回true,失败返回false
 *  \note   每次只允许读取一条记录
 */
bool SqliteWrapper::selectBlob(const std::string& sql,std::string bindVarName,char* buf, int& len)
{
    sqlite3_stmt* pStmt;
    int colIndex = 0;
    if (SQLITE_OK != sqlite3_prepare(m_db, sql.c_str(), -1, &pStmt, NULL))
    {
        TRACE_ERR_CLASS("sqlite3_prepare error.\n");
        sqlite3_finalize(pStmt);
        return false;
    }
    
    if (SQLITE_ROW != sqlite3_step(pStmt))
    {
        TRACE_ERR_CLASS("sqlite3_step error or finished.\n");
        sqlite3_finalize(pStmt);
        return false;
    }

    colIndex = sqlite3_bind_parameter_index(pStmt,bindVarName.c_str());
    const void *pData = sqlite3_column_blob(pStmt, colIndex);
    len = sqlite3_column_bytes(pStmt, colIndex);
    memcpy(buf,pData,len);
    sqlite3_finalize(pStmt);
    return true;
}
}
#endif
